//---------------------------
// Includes
//---------------------------
#include "StdAfx.h"
#include "Cube.h"
#include "Level.h"
#include "GraphCamera.h"
#include "CubePhysX.h"
#include "NxShape.h"
#include "NxActor.h"
//#include "NxPhysics.h"
//---------------------------
// Defines
//---------------------------
//#define GAME_ENGINE (GameEngine::GetSingleton())

//---------------------------
// Constructor & Destructor
//---------------------------
Cube::Cube(Level *pLevel, float width, float height, float depth, D3DXCOLOR color)
:LevelElement()
	,m_pVertexLayout(0)
	,m_pVertexBuffer(0)
	,m_pIndexBuffer(0)
	,m_pDefaultEffect(0)	
	,m_pDefaultTechnique(0)	
	,m_pWorldViewProjectionVariable(NULL)
	,m_pWorldVariable(0)
	,m_pLightDirVariabele(0)
	,m_Width(width)
	,m_Height(height)
	,m_Depth(depth)
	,m_Color(color)
	,m_pActor(0)
	,m_bRigid(true)
	,m_pPhysXMesh(0)

{
	m_pLevel = pLevel;
}

Cube::~Cube()
{
	SafeRelease(m_pVertexBuffer );
	SafeRelease(m_pVertexLayout);
}

void Cube::Initialize(ContentManager *pContentManager)
{
	CreateEffect(pContentManager);
	DefineInputlayout();
	BuildShape();
	BuildVertexBuffer();
	BuildIndexBuffer();
	m_pPhysXMesh = new CubePhysX(m_pLevel,m_Width,m_Height,m_Depth,m_Color,CubePhysX::RIGID);
	//m_pPhysXMesh->Translate(m_Pos);

	m_pPhysXMesh->GetActor()->userData = this;
}
void Cube::Tick(const InputState & refInputState)
{
	//m_pPhysXMesh->AddForce(D3DXVECTOR3(0, 0, 0));
	m_pPhysXMesh->Tick(refInputState);
	D3DXMATRIX world = m_pPhysXMesh->GetWorldMatrix();
	LevelElement::SetWorldMatrix(world);
}
void Cube::Draw(const RenderContext* pRenderContext, ID3D10ShaderResourceView* shadowdepthmap)
{
	if(!m_pDefaultTechnique )
	{
		MessageBox(0,_T("No Technique"),_T("ERROR"),0);
		return;
	}
	if(!m_pVertexBuffer)
	{
		MessageBox(0,_T("No Vertices"),_T("ERROR"),0);
		return;
	}	
	// Update Shader matrix variables
	D3DXMATRIX matView = pRenderContext->GetCamera()->GetView();
	D3DXMATRIX matProj = pRenderContext->GetCamera()->GetProj();
	m_pWorldViewProjectionVariable->SetMatrix((float*)&(m_World*matView*matProj));
	m_pWorldVariable->SetMatrix((float*)&(m_World));

	D3DXVECTOR3 lightDir = pRenderContext->GetLight().dir;
	m_pLightDirVariabele->SetFloatVectorArray(&lightDir.x,0,sizeof(D3DXVECTOR3)/sizeof(float));

	// Set the input layout
    m_pLevel->GetDevice()->IASetInputLayout( m_pVertexLayout );

    // Set vertex buffer(s)
    UINT offset = 0;
	UINT vertexBufferStride = sizeof(VertexPosNormCol);
    m_pLevel->GetDevice()->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &vertexBufferStride, &offset );
   	
	// Set index buffer
	m_pLevel->GetDevice()->IASetIndexBuffer(m_pIndexBuffer,DXGI_FORMAT_R32_UINT,0);

    // Set primitive topology
    m_pLevel->GetDevice()->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

    D3D10_TECHNIQUE_DESC techDesc;
    m_pDefaultTechnique->GetDesc( &techDesc );
    for( UINT p = 0; p < techDesc.Passes; ++p )
    {
        m_pDefaultTechnique->GetPassByIndex(p)->Apply(0);
		m_pLevel->GetDevice()->DrawIndexed( m_VecIndices.size(), 0, 0 ); 
    }
}
void Cube::CreateEffect(ContentManager *pContentManager)
{
	m_pDefaultEffect = pContentManager->GetEffect(m_pLevel->GetDevice(),  _T("./Effect/PosNormCol.fx"));
	
	//get first technique found
	m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByIndex(0);
	if(!m_pDefaultTechnique->IsValid())MessageBox(0,_T("Technique not valid"),_T("ERROR"),0);

	GetEffectVariables(m_pDefaultEffect);
}
void Cube::GetEffectVariables(ID3D10Effect* pEffect)
{
	//get effect variables
	m_pWorldViewProjectionVariable = pEffect->GetVariableBySemantic("WorldViewProjection")->AsMatrix();
	if(!m_pWorldViewProjectionVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic WorldViewProjection Failed"),_T("ERROR"),0);

	m_pWorldVariable = pEffect->GetVariableBySemantic("World")->AsMatrix();
	if(!m_pWorldVariable->IsValid())MessageBox(0,_T("Getting EffectSemantic World Failed"),_T("ERROR"),0);

	m_pLightDirVariabele = pEffect->GetVariableBySemantic("LightDir")->AsVector();
	if(!m_pLightDirVariabele->IsValid())MessageBox(0,_T("Getting EffectSemantic LightDir Failed"),_T("ERROR"),0);
}
void Cube::DefineInputlayout()
{
    // Define the input layout
    D3D10_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },  
        { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },  
        { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 }, 
    };
    UINT numElements = sizeof(layout)/sizeof(layout[0]);

    // Create the input layout
    D3D10_PASS_DESC PassDesc;
	// Get the pass decriptor from the effect technique
    m_pDefaultTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    HR(m_pLevel->GetDevice()->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &m_pVertexLayout ));


}

void Cube::BuildShape()
{
	//front red
	VertexPosNormCol v(D3DXVECTOR3(-m_Width/2,  -m_Height/2, -m_Depth/2),D3DXVECTOR3(0,  -0, -1),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2,   m_Height/2, -m_Depth/2),D3DXVECTOR3(-0,  -0, -1),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3( m_Width/2,  -m_Height/2, -m_Depth/2),D3DXVECTOR3(-0,  -0, -1),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3( m_Width/2,   m_Height/2, -m_Depth/2),D3DXVECTOR3(-0,  -0, -1),m_Color);
	m_VecVertices.push_back(v);
	//back red
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2, -m_Height/2, m_Depth/2),D3DXVECTOR3(0,  0, 1),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2,  m_Height/2, m_Depth/2),D3DXVECTOR3(0,  0, 1),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3( m_Width/2, -m_Height/2, m_Depth/2),D3DXVECTOR3(0,  0, 1),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3( m_Width/2,  m_Height/2, m_Depth/2),D3DXVECTOR3(0,  0, 1),m_Color);
	m_VecVertices.push_back(v);

	//left red
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2, -m_Height/2, -m_Depth/2),D3DXVECTOR3(-1,  0, 0),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2,  m_Height/2, -m_Depth/2),D3DXVECTOR3(-1,  0, 0),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2, -m_Height/2,  m_Depth/2),D3DXVECTOR3(-1,  0, 0),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2,  m_Height/2,  m_Depth/2),D3DXVECTOR3(-1,  0, 0),m_Color);
	m_VecVertices.push_back(v);

	//right red
	v=VertexPosNormCol(D3DXVECTOR3(m_Width/2, -m_Height/2, -m_Depth/2),D3DXVECTOR3(1,  0, 0),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(m_Width/2,  m_Height/2, -m_Depth/2),D3DXVECTOR3(1,  0, 0),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(m_Width/2, -m_Height/2,  m_Depth/2),D3DXVECTOR3(1,  0, 0),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(m_Width/2,  m_Height/2,  m_Depth/2),D3DXVECTOR3(1,  0, 0),m_Color);
	m_VecVertices.push_back(v);

	//top blue
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2,  m_Height/2,  m_Depth/2),D3DXVECTOR3(0,  1, 0),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2,  m_Height/2, -m_Depth/2),D3DXVECTOR3(0,  1, 0),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(m_Width/2,  m_Height/2,   m_Depth/2),D3DXVECTOR3(0,  1, 0),m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(m_Width/2,  m_Height/2,  -m_Depth/2),D3DXVECTOR3(0,  1, 0),m_Color);
	m_VecVertices.push_back(v);

	//bottom blue
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2,  -m_Height/2,  m_Depth/2),D3DXVECTOR3(0,  -1, 0), m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3(-m_Width/2,  -m_Height/2, -m_Depth/2),D3DXVECTOR3(0,  -1, 0), m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3( m_Width/2,  -m_Height/2,  m_Depth/2),D3DXVECTOR3(0,  -1, 0), m_Color);
	m_VecVertices.push_back(v);
	v=VertexPosNormCol(D3DXVECTOR3( m_Width/2,  -m_Height/2, -m_Depth/2),D3DXVECTOR3(0,  -1, 0), m_Color);
	m_VecVertices.push_back(v);

	//front
	AddTriangle(0,1,2);
	AddTriangle(2,1,3);
	//back
	AddTriangle(4,6,5);
	AddTriangle(5,6,7);
	//left
	AddTriangle(8,10,9);
	AddTriangle(9,10,11);
	//right
	AddTriangle(12,13,14);
	AddTriangle(14,13,15);
	//top
	AddTriangle(16,18,17);
	AddTriangle(17,18,19);
	//bottom
	AddTriangle(20,21,22);
	AddTriangle(22,21,23);
}	


void Cube::AddTriangle (unsigned int a, unsigned int b, unsigned c)
{
	m_VecIndices.push_back(a);
	m_VecIndices.push_back(b);
	m_VecIndices.push_back(c);
}

void Cube::BuildVertexBuffer()
{
	//fill a buffer description to copy the vertexdata into graphics memory
	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( VertexPosNormCol ) * m_VecVertices.size();
	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;

	D3D10_SUBRESOURCE_DATA initData;
	initData.pSysMem = m_VecVertices.data();
	//create a ID3D10Buffer in graphics memory containing the vertex info
	HR(m_pLevel->GetDevice()->CreateBuffer( &bd, &initData, &m_pVertexBuffer ));
}
void Cube::BuildIndexBuffer()
{
	D3D10_BUFFER_DESC ibd;
    ibd.Usage = D3D10_USAGE_IMMUTABLE;
    ibd.ByteWidth = sizeof(DWORD) * m_VecIndices.size();
    ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    ibd.MiscFlags = 0;
    D3D10_SUBRESOURCE_DATA initData;
    initData.pSysMem = m_VecIndices.data();
    HR(m_pLevel->GetDevice()->CreateBuffer(&ibd, &initData, &m_pIndexBuffer));
}

void Cube::Translate(const D3DXVECTOR3 pos)
{
	m_pPhysXMesh->Translate(pos);
	m_Pos = pos;
	LevelElement::Translate(pos); //Hierdoor geven we de actor onze eigen world matrix
}

void Cube::Rotate(const D3DXVECTOR3 angles)
{
	LevelElement::Rotate(angles);
}

void Cube::Scale(const D3DXVECTOR3 scales)
{
	LevelElement::Scale(scales);
}